package is.glif.fenius.translators.glambda;

import is.glif.fenius.util.ConfigManager;

import is.glif.fenius.api.FCreateReq;
import is.glif.fenius.api.FCreateResp;
import is.glif.fenius.api.FCancelReq;
import is.glif.fenius.api.FCancelResp;
import is.glif.fenius.api.FListReq;
import is.glif.fenius.api.FListResp;
import is.glif.fenius.api.FAvailReq;
import is.glif.fenius.api.FAvailResp;
import is.glif.fenius.api.FQueryReq;
import is.glif.fenius.api.FQueryResp;
import is.glif.fenius.api.FListResp;
import is.glif.fenius.api.FExternalFault;
import is.glif.fenius.api.FInternalFault;

import is.glif.fenius.api.FReservation;
import is.glif.fenius.api.FReservationReqParams;
import is.glif.fenius.api.FReservationStatus;
import is.glif.fenius.api.FActivationStatus;
import is.glif.fenius.api.Translator;
import is.glif.fenius.api.TranslatorFactory;

import java.util.Calendar;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Date;
import java.util.TimeZone;
import java.util.List;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;

import net.glambda.schemas.gnswsi3._2008._12.rdl.TimeframeType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.ExactTimeframeType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.CoallocationTimeframeType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.CoallocationTimeSpecificationType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.ReservationStatusType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.ResourceAttributeType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.ReservationResourcesType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.NetworkResourcesType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.ResourceRequirementsType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.TimeSpecificationType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.ResourceStatusType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.AvailableResourceQueryType;
import net.glambda.schemas.gnswsi3._2008._12.rdl.AvailableResourceQueryResultType;

import net.glambda.schemas.gnswsi3._2008._12.ndl.MediaTypeType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.TerminationPointType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.EndpointType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.RouteType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.GeneralBWType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.BWUnitType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.BandwidthType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.SwitchingSchemeType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.EthernetParametersType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.MPLSParametersType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.IPParametersType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.PathPropertiesType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.PathType;
import net.glambda.schemas.gnswsi3._2008._12.ndl.NetworkResourceSLADocumentType;

import org.ietf.jgss.GSSCredential;

import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService
public class GlambdaTranslator implements Translator {
    static public boolean debug = true;
    private static int no = 0;
    static String domain = null;
    static String service = null;
    static String DN = null;
    static GSSCredential credential = null;
    static int adjustTime = 0;
    static int bwunit = 1000000;

    private static Hashtable<String, ResourceManagerClient> rms;
    private static Hashtable<String, FReservation> resvs;
    private static Hashtable<String, String> subkeys;
    private static LinkedList<String> ids;

    static {
	System.err.println("== GlambdaTranslator:static:start");
	rms = new Hashtable<String, ResourceManagerClient>();
	resvs = new Hashtable<String, FReservation>();
	subkeys = new Hashtable<String, String>();
	ids = new LinkedList<String>();
	TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
	// TimeZone.setDefault(TimeZone.getTimeZone("GMT-8"));
	System.err.println("== GlambdaTranslator:static:end");
    }

    public GlambdaTranslator() 
    {
	System.err.println("== GlambdaTranslator:new");
        loadConfig();
    }

    @WebMethod
    public FCreateResp create(FCreateReq r) 
	throws FInternalFault, FExternalFault
    {
	long T_create_s = System.nanoTime()/1000;
	long T_create_reserve_s = 0;
	long T_create_reserve_e = 0;
	long T_create_getprop_s = 0;
	long T_create_getprop_e = 0;
	long T_create_e = 0;

	if (debug) System.err.println("== GlambdaTranslator:create:in");
	no ++;
	String coid = "coid-" + no;
	String reservationId = "[" + no + "]:";

	FReservationReqParams params = r.getResvParams();
	FReservation resv = getReservation(params);
	resv.setReservationId(reservationId);
	resv.setReservationStatus(FReservationStatus.RESERVING);
	resv.setActivationStatus(FActivationStatus.INACTIVE);

	Date activationTime = params.getActivationTime();
	Integer duration = params.getDuration();
	Integer bandwidth = params.getBandwidth();
	String srcEndpoint = params.getSrcEndpoint();
	String dstEndpoint = params.getDstEndpoint();
	String srcVlanTag = params.getSrcVlanTag();
	String dstVlanTag = params.getDstVlanTag();
	Integer vlan = null;

	if (debug || true) {
	    System.err.println("== GlambdaTranslator:id      =" + reservationId);
	    System.err.println("== GlambdaTranslator:date    =" + activationTime);
	    System.err.println("== GlambdaTranslator:duration=" + duration);
	    System.err.println("== GlambdaTranslator:bw      =" + bandwidth);
	    System.err.println("== GlambdaTranslator:a-point =" + srcEndpoint);
	    System.err.println("== GlambdaTranslator:z-point =" + dstEndpoint);
	    System.err.println("== GlambdaTranslator:src vlan=" + srcVlanTag);
	    System.err.println("== GlambdaTranslator:dst vlan=" + dstVlanTag);
	}

	if (srcVlanTag == null && dstVlanTag == null) vlan = 0;
	else if (srcVlanTag != null && srcVlanTag.equals(dstVlanTag)) {
	    try {
		vlan = Integer.valueOf(srcVlanTag);
	    } catch (NumberFormatException ex) {
		throw new FExternalFault("srcVlanTag("+ srcVlanTag + 
					 ") is not NumberFormat.");
	    }
	} else {
	    throw new FInternalFault("Different src/dst vlan tags not supported.");
	}

	Calendar startTime = Calendar.getInstance();
	startTime.setTime(activationTime);
	startTime.set(Calendar.MILLISECOND, 0);
	Calendar endTime = (Calendar) startTime.clone();
	endTime.set(Calendar.MILLISECOND, 0);
	endTime.add(Calendar.SECOND, duration);
	if (adjustTime != 0) {
	    startTime.add(Calendar.HOUR_OF_DAY, adjustTime);
	    endTime.add(Calendar.HOUR_OF_DAY, adjustTime);
	}

	ExactTimeframeType etf = new ExactTimeframeType();
	etf.setStartTime(startTime);
	etf.setEndTime(endTime);
	
	CoallocationTimeframeType[] ctf = new CoallocationTimeframeType[1];
        ctf[0] = new CoallocationTimeframeType();
	ctf[0].setCoallocationTimeframeID(coid);
	ctf[0].setTimeframe((TimeframeType) etf);
	
	CoallocationTimeSpecificationType cts =
            new CoallocationTimeSpecificationType();
	cts.setCoallocationTimeframeID(coid);
        TimeSpecificationType ts = (TimeSpecificationType) cts;
	    
	MediaTypeType media = null;
        TerminationPointType[] a_tp = new TerminationPointType[1];
        a_tp[0] = new TerminationPointType();
	a_tp[0].setTerminationPointName(srcEndpoint);
	a_tp[0].setMediaType(media);
        TerminationPointType[] z_tp = new TerminationPointType[1];
        z_tp[0] = new TerminationPointType();
	z_tp[0].setTerminationPointName(dstEndpoint);
	z_tp[0].setMediaType(media);

        EndpointType a_ep = new EndpointType();
	a_ep.setDomainName(domain);
	List<TerminationPointType> l_a_ep = a_ep.getTerminationPoint();
	l_a_ep.add(a_tp[0]);
        EndpointType z_ep = new EndpointType();
	z_ep.setDomainName(domain);
	List<TerminationPointType> l_z_ep = z_ep.getTerminationPoint();
	l_z_ep.add(z_tp[0]);
            
	RouteType route = null;

        GeneralBWType minbw = new GeneralBWType();
	bandwidth *= bwunit;
	minbw.setRate(bandwidth);
	minbw.setBWUnit(BWUnitType.BPS);
        GeneralBWType maxbw = new GeneralBWType();
	maxbw.setRate(bandwidth);
	maxbw.setBWUnit(BWUnitType.BPS);
        GeneralBWType peakbw = new GeneralBWType();
	peakbw.setRate(bandwidth);
	peakbw.setBWUnit(BWUnitType.BPS);
        GeneralBWType guardbw = new GeneralBWType();
	guardbw.setRate(bandwidth);
	guardbw.setBWUnit(BWUnitType.BPS);
	BandwidthType bw = new BandwidthType();
	bw.setMinimumBW(minbw);
	bw.setMaximumBW(maxbw);
	bw.setPeakBW(peakbw);
	bw.setGuaranteedBW(guardbw);

	Float avail = new Float(0);
        Integer delay = new Integer(10);
        SwitchingSchemeType sw = SwitchingSchemeType.ETHERNET;
        EthernetParametersType ether = new EthernetParametersType();
	ether.setMTU(new Integer(1500));
	ether.setVLANTagID(vlan);
        ether.setCoS(new Integer(0));

	MPLSParametersType mpls = null;
        IPParametersType ip = null;
        PathPropertiesType prop = new PathPropertiesType();
	prop.setAvailability(avail);
	prop.setTransmissionDelay(delay);
	prop.setSwitchingScheme(sw);
	prop.setEthernetParameters(ether);
	prop.setMPLSParameters(mpls);
	prop.setIPParameters(ip);

        PathType path = new PathType();
	path.setAPoint(a_ep);
	path.setZPoint(z_ep);
	path.setRoute(route);
	path.setBandwidth(bw);
	path.setPathProperties(prop);

	NetworkResourceSLADocumentType slad = null;
        NetworkResourcesType nr1 = new NetworkResourcesType();
	nr1.setReservationID(null);
	nr1.setReservationStatus(null);
	nr1.setTimeSpecification(ts);
	nr1.setPath(path);
	nr1.setNetworkResourceSLADocument(slad);
        List<ResourceAttributeType> attr = nr1.getResourceAttribute();

        ReservationResourcesType[] rr = new ReservationResourcesType[1];
	rr[0] = (ReservationResourcesType) nr1;
	ResourceRequirementsType request = new ResourceRequirementsType();
	List<CoallocationTimeframeType> l_ctf = request.getCoallocationTimeframe();
	l_ctf.add(ctf[0]);
	List<ReservationResourcesType> l_rrt = request.getReservationResources();
	l_rrt.add(rr[0]);
	
	resvs.put(reservationId, resv); /* keep reservation */
	String subkey = reservationId;
	resv.setReservationStatus(FReservationStatus.RESERVING);

	try {
	    if (debug) System.err.println("== GlambdaTranslator:create:start.");
	    T_create_reserve_s = System.nanoTime()/1000;
	    ResourceManagerClient nrm = new ResourceManagerClient(service, DN, null);
	    nrm.reserve(request);
	    T_create_reserve_e = System.nanoTime()/1000;

	    if (debug) System.err.println("== GlambdaTranslator:create:end.");

	    T_create_getprop_s = System.nanoTime()/1000;
	    ReservationResourcesType[] rrt = nrm.getReservationResource();
	    T_create_getprop_e = System.nanoTime()/1000;
	    if (true) nrm.printResultMeasurement();

	    Integer vlanid = new Integer(0);
	    if (rrt[0] != null) {
		subkey = rrt[0].getReservationID();

		NetworkResourcesType nrt = (NetworkResourcesType) rrt[0];
		vlanid = nrt.getPath().getPathProperties().getEthernetParameters().
		    getVLANTagID();
		
		if (debug || true) 
		    System.err.println("== GlambdaTranslator:create:ID=" + reservationId 
				       + ", subkey=" + subkey 
				       + ", vlan=" + vlanid);
	    }

	    subkeys.put(reservationId, subkey);
	    rms.put(reservationId, nrm);
	    resv.setReservationStatus(FReservationStatus.RESERVED);
	    resv.setActivationStatus(FActivationStatus.INACTIVE);
	} catch (Exception ex) {
	    if (debug) System.err.println("== GlambdaTranslator:create:exception.");
	    resv.setReservationStatus(FReservationStatus.FAILED);

	    ex.printStackTrace();
	    FInternalFault f = new FInternalFault();
	    f.setMessage(ex.toString());
	    throw f;
	}

	FCreateResp result = new FCreateResp();
	result.setResvParams(resv);

	if (debug) System.err.println("== GlambdaTranslator:create:end");
	T_create_e = System.nanoTime()/1000;
	if (debug) System.err.println("CREATE:\t" + (T_create_reserve_s - T_create_s) +
				      "\t" + (T_create_reserve_e - T_create_s) +
				      "\t" + (T_create_getprop_s - T_create_s) +
				      "\t" + (T_create_getprop_e - T_create_s) +
				      "\t" + (T_create_e - T_create_s));
	return result;
    }
	
    @WebMethod
    public FCancelResp cancel(FCancelReq r) 
	throws FInternalFault, FExternalFault 
    {
	FCancelResp cr = new FCancelResp();
	cr.setReservationStatus(FReservationStatus.FAILED);

	String reservationId  = r.getReservationId();
	if (debug || true) System.err.println("== GlambdaTranslator:cancel:ID=" +
					      reservationId);

	FReservation resv = resvs.get(reservationId);
	if (debug || true) System.err.println("== GlambdaTranslator:cancel:resvs=" 
					      + resv);
	if (resv == null) return cr;

	FReservationStatus status = resv.getReservationStatus();
	if (debug || true) System.err.println("== GlambdaTranslator:cancel:resvs=" 
					      + status);
	if (status == null) return cr;
	if (status == FReservationStatus.FINISHED ||
	    status == FReservationStatus.FAILED) {
	    return cr;
	}

	String[] subkey = new String[1];
	subkey[0] = subkeys.get(reservationId);
	if (debug || true) System.err.println("== GlambdaTranslator:cancel:ID=" 
					      + reservationId 
					      + ", subkey=" + subkey[0]);

	ResourceManagerClient nrm = rms.get(reservationId);
	if (nrm == null || resv == null || subkey[0] == null) return cr;

	resv.setReservationStatus(FReservationStatus.RELEASING);
	try {
	    if (debug) System.err.println("== GlambdaTranslator:cancel start.");
	    nrm.release(subkey);
	    if (debug) System.err.println("== GlambdaTranslator:cancel end.");
	} catch (Exception ex) {
	    if (debug) System.err.println("== GlambdaTranslator:cancel exception.");
	    ex.printStackTrace();
	    
	    resv.setReservationStatus(FReservationStatus.FAILED);
	    resv.setActivationStatus(FActivationStatus.FAILED);
	    rms.remove(reservationId);
	    subkeys.remove(reservationId);
	    /* keep reservation, do not call resvs.remove(reservationId) */

	    FInternalFault f = new FInternalFault();
	    f.setMessage(ex.toString());
	    throw f;
	}

	resv.setReservationStatus(FReservationStatus.RELEASED);
	resv.setActivationStatus(FActivationStatus.INACTIVE);
	rms.remove(reservationId);
	subkeys.remove(reservationId);
	/* keep reservation, do not call resvs.remove(reservationId) */

	cr.setReservationStatus(resv.getReservationStatus());
	return cr;
    }

    @WebMethod
    public FListResp list(FListReq r)
	throws FInternalFault, FExternalFault
    {
	FListResp result = new FListResp();
	ArrayList<FReservation> rlist = new ArrayList<FReservation>();
	Hashtable<String, FReservation> rhash = new Hashtable<String, FReservation>();

	Enumeration e = resvs.keys();
	while (e.hasMoreElements()) {
	    String id = (String) e.nextElement();
	    FReservation resv = resvs.get(id);
	    rlist.add(resv);
	    rhash.put(id, resv);
	}

	if (r == null) {
	    /* all reservations are matched. */

	} else if ((rlist.size() != 0) && (r.getReservationIds() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    List<String> ids = r.getReservationIds();

	    int size = ids.size();
	    for (int i = 0; i < size; i++) {
		String id = ids.get(i);
		FReservation resv = rhash.get(id);

		if (resv != null) list.add(resv);
	    }
	    rlist = list;

	} else if ((rlist.size() != 0) && (r.getDescriptors() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    List<String> descriptors = r.getDescriptors();
	    int size = descriptors.size();

	    for (int k = 0; k < rlist.size(); k++) {
		FReservation resv = rlist.get(k);
		String[] d = resv.getDescriptors();
		boolean flag = false;
		
		for (int i = 0; i < size; i++) {
		    String desc = descriptors.get(i);
		    if (desc == null || desc.equals("")) continue;
			    
		    if (d != null && d.length != 0) {
			for (int m = 0; m < d.length; m++) {
			    if (desc.equals(d[m])) {
				list.add(resv);
				flag = true;
				break;
			    }
			}
		    }
		    if (flag) break;
		}
	    }
	    rlist = list;

	} else if ((rlist.size() != 0) && (r.getStatuses() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    List<String> statuses = r.getStatuses();
	    int size = statuses.size();

	    for (int k = 0; k < rlist.size(); k++) {
		FReservation resv = rlist.get(k);
		FReservationStatus s = resv.getReservationStatus();

		for (int i = 0; i < size; i++) {
		    String status = statuses.get(i);
		    if (status == null || status.equals("")) continue;
		    
		    if (s == null) continue;
		    
		    if (status.equals(s.value())) {
			list.add(resv);
			break;
		    }
		}
	    }
	    rlist = list;

	} else if ((rlist.size() != 0) && (r.getStartingAfter() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    Date d = r.getStartingAfter();

	    for (int k = 0; k < rlist.size(); k++) {
		FReservation resv = rlist.get(k);
		Date start = resv.getActivationTime();
		
		if ((d == null) || d.after(start)) {
		    list.add(resv);
		    continue;
		}
	    }
	    rlist = list;

	} else if ((rlist.size() != 0) && (r.getStartingBefore() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    Date d = r.getEndingBefore();

	    for (int k = 0; k < rlist.size(); k++) {
		FReservation resv = rlist.get(k);
		Date start = resv.getActivationTime();
		
		if ((d == null) || d.before(start)) {
		    list.add(resv);
		    continue;
		}
	    }
	    rlist = list;

	} else if ((rlist.size() != 0) && (r.getEndingAfter() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    Date d = r.getStartingAfter();

	    for (int k = 0; k < rlist.size(); k++) {
		FReservation resv = rlist.get(k);
		Date start = resv.getActivationTime();
		Date end = new Date(start.getTime() + (long) resv.getDuration());
		
		if ((d == null) || d.after(end)) {
		    list.add(resv);
		    continue;
		}
	    }
	    rlist = list;

	} else if ((rlist.size() != 0) && (r.getEndingBefore() != null)) {
	    ArrayList<FReservation> list = new ArrayList<FReservation>();
	    Date d = r.getEndingBefore();

	    for (int k = 0; k < rlist.size(); k++) {
		FReservation resv = rlist.get(k);
		Date start = resv.getActivationTime();
		Date end = new Date(start.getTime() + (long) resv.getDuration());
		
		if ((d == null) || d.before(end)) {
		    list.add(resv);
		    continue;
		}
	    }
	    rlist = list;
	}

	int size = rlist.size();
	if (size == 0) return result;

	/* update status */
	for (int k = 0; k < size; k++) {
	    FReservation resv = rlist.get(k);
	    FReservationStatus status = resv.getReservationStatus();
	    if (status == FReservationStatus.FINISHED ||
		status == FReservationStatus.RELEASED ||
		status == FReservationStatus.FAILED) {
		continue;
	    }
	    
	    String[] subkey = new String[1];
	    String reservationId = resv.getReservationId();
	    subkey[0] = subkeys.get(reservationId);
	    if (subkey[0] == null) continue;
		
	    ResourceManagerClient nrm = rms.get(reservationId);
	    if (nrm == null) {
		resv.setReservationStatus(FReservationStatus.FAILED);
		resv.setActivationStatus(FActivationStatus.FAILED);
		continue;
	    }

	    try {
		ReservationStatusType[] gstatus = nrm.getReservationStatus(subkey);
		convertStatus(resv, gstatus[0]);

	    } catch (Exception ex) {
		if (debug) System.err.println("== GlambdaTranslator:list:exception.");
		ex.printStackTrace();

		resv.setReservationStatus(FReservationStatus.FAILED);
		resv.setActivationStatus(FActivationStatus.FAILED);
		rms.remove(reservationId);
		subkeys.remove(reservationId);
		/* keep reservation, do not call resvs.remove(reservationId) */
	    }
	}

	result.setReservations(rlist);
        return result;
    }
    
    @WebMethod
    public FAvailResp isAvailable(FAvailReq r) 
	throws FInternalFault, FExternalFault
    {
	FAvailResp resp = new FAvailResp();
	resp.setAvailable(false);

	if (r == null || r.getResvParams() == null) return resp;

	FReservationReqParams req = r.getResvParams();
	if (debug) System.err.println("== GlambdaTranslator:available:in");

	FReservationReqParams params = r.getResvParams();

	Date activationTime = params.getActivationTime();
	Integer duration = params.getDuration();
	Integer bandwidth = params.getBandwidth();
	String srcEndpoint = params.getSrcEndpoint();
	String dstEndpoint = params.getDstEndpoint();
	String srcVlanTag = params.getSrcVlanTag();
	String dstVlanTag = params.getDstVlanTag();
	Integer vlan = null;

	if (debug || true) {
	    System.err.println("== GlambdaTranslator:id      = null");
	    System.err.println("== GlambdaTranslator:date    =" + activationTime);
	    System.err.println("== GlambdaTranslator:duration=" + duration);
	    System.err.println("== GlambdaTranslator:bw      =" + bandwidth);
	    System.err.println("== GlambdaTranslator:a-point =" + srcEndpoint);
	    System.err.println("== GlambdaTranslator:z-point =" + dstEndpoint);
	    System.err.println("== GlambdaTranslator:src vlan=" + srcVlanTag);
	    System.err.println("== GlambdaTranslator:dst vlan=" + dstVlanTag);
	}

	if (srcVlanTag == null && dstVlanTag == null) vlan = 0;
	else if (srcVlanTag != null && srcVlanTag.equals(dstVlanTag)) {
	    try {
		vlan = Integer.valueOf(srcVlanTag);
	    } catch (NumberFormatException ex) {
		throw new FExternalFault("srcVlanTag("+ srcVlanTag + 
					 ") is not NumberFormat.");
	    }
	} else {
	    return resp;
	}

	Calendar startTime = Calendar.getInstance();
	startTime.setTime(activationTime);
	startTime.set(Calendar.MILLISECOND, 0);
	Calendar endTime = (Calendar) startTime.clone();
	endTime.set(Calendar.MILLISECOND, 0);
	endTime.add(Calendar.SECOND, duration);
	if (adjustTime != 0) {
	    startTime.add(Calendar.HOUR_OF_DAY, adjustTime);
	    endTime.add(Calendar.HOUR_OF_DAY, adjustTime);
	}

	ExactTimeframeType etf = new ExactTimeframeType();
	etf.setStartTime(startTime);
	etf.setEndTime(endTime);
        TimeSpecificationType ts = (TimeSpecificationType) etf;
	    
	MediaTypeType media = null;
        TerminationPointType[] a_tp = new TerminationPointType[1];
        a_tp[0] = new TerminationPointType();
	a_tp[0].setTerminationPointName(srcEndpoint);
	a_tp[0].setMediaType(media);
        TerminationPointType[] z_tp = new TerminationPointType[1];
        z_tp[0] = new TerminationPointType();
	z_tp[0].setTerminationPointName(dstEndpoint);
	z_tp[0].setMediaType(media);

        EndpointType a_ep = new EndpointType();
	a_ep.setDomainName(domain);
	List<TerminationPointType> l_a_ep = a_ep.getTerminationPoint();
	l_a_ep.add(a_tp[0]);
        EndpointType z_ep = new EndpointType();
	z_ep.setDomainName(domain);
	List<TerminationPointType> l_z_ep = z_ep.getTerminationPoint();
	l_z_ep.add(z_tp[0]);
            
	RouteType route = null;

        GeneralBWType minbw = new GeneralBWType();
	bandwidth *= bwunit;
	minbw.setRate(bandwidth);
	minbw.setBWUnit(BWUnitType.BPS);
        GeneralBWType maxbw = new GeneralBWType();
	maxbw.setRate(bandwidth);
	maxbw.setBWUnit(BWUnitType.BPS);
        GeneralBWType peakbw = new GeneralBWType();
	peakbw.setRate(bandwidth);
	peakbw.setBWUnit(BWUnitType.BPS);
        GeneralBWType guardbw = new GeneralBWType();
	guardbw.setRate(bandwidth);
	guardbw.setBWUnit(BWUnitType.BPS);
	BandwidthType bw = new BandwidthType();
	bw.setMinimumBW(minbw);
	bw.setMaximumBW(maxbw);
	bw.setPeakBW(peakbw);
	bw.setGuaranteedBW(guardbw);

	Float avail = new Float(0);
        Integer delay = new Integer(10);
        SwitchingSchemeType sw = SwitchingSchemeType.ETHERNET;
        EthernetParametersType ether = new EthernetParametersType();
	ether.setMTU(new Integer(1500));
	ether.setVLANTagID(vlan);
        ether.setCoS(new Integer(0));

	MPLSParametersType mpls = null;
        IPParametersType ip = null;
        PathPropertiesType prop = new PathPropertiesType();
	prop.setAvailability(avail);
	prop.setTransmissionDelay(delay);
	prop.setSwitchingScheme(sw);
	prop.setEthernetParameters(ether);
	prop.setMPLSParameters(mpls);
	prop.setIPParameters(ip);

        PathType path = new PathType();
	path.setAPoint(a_ep);
	path.setZPoint(z_ep);
	path.setRoute(route);
	path.setBandwidth(bw);
	path.setPathProperties(prop);

	NetworkResourceSLADocumentType slad = null;

        NetworkResourcesType nr1 = new NetworkResourcesType();
	nr1.setReservationID(null);
	nr1.setReservationStatus(null);
	nr1.setTimeSpecification(ts);
	nr1.setPath(path);
	nr1.setNetworkResourceSLADocument(slad);
        List<ResourceAttributeType> attr = nr1.getResourceAttribute();

        ReservationResourcesType[] rr = new ReservationResourcesType[1];
	rr[0] = (ReservationResourcesType) nr1;
	
	try {
	    if (debug) System.err.println("== GlambdaTranslator:available:start.");
	    ResourceManagerClient nrm = new ResourceManagerClient(service, DN, null);
	    ResourceStatusType[] result = nrm.checkResourceAvailability(DN, null, rr);
		
	    if (debug) System.err.println("== GlambdaTranslator:available:end.");
	    
	    if (result[0] == ResourceStatusType.AVAILABLE) resp.setAvailable(true);
	} catch (Exception ex) {
	    if (debug) System.err.println("== GlambdaTranslator:available:exception.");

	    ex.printStackTrace();
	    FInternalFault f = new FInternalFault();
	    f.setMessage(ex.toString());
	    throw f;
	}

	return resp;
    }

    @WebMethod
    public FQueryResp query(FQueryReq r) 
	throws FInternalFault, FExternalFault
    {
	FQueryResp resp = new FQueryResp();

	if (r == null || 
	    (r.getReservationId() == null && r.getDescriptor() == null)) {
	    return resp;
	}

	String reservationId = r.getReservationId();
	{
	    FReservation resv = resvs.get(reservationId);
	    if (resv != null) {
		resp.setResvParams(resv);
		return resp;
	    }
	}

	String descriptor = r.getDescriptor();
	if (descriptor == null) return resp;

	Enumeration e = resvs.keys();
	while (e.hasMoreElements()) {
	    String id = (String) e.nextElement();
	    FReservation resv = resvs.get(id);

	    String[] d = resv.getDescriptors();
	    if (d == null) return resp;

	    for (int i = 0; i < d.length; i++) {
		if (descriptor.equals(d[i])) {
		    resp.setResvParams(resv);
		    return resp;
		}
	    }
	}
	return resp;
    }

    private void loadConfig()
    {
	if (service == null) {
	    System.err.println("== GlambdaTranslator:loadConfig:start");

	    try {
		ConfigManager cm = ConfigManager.getInstance();
		Map config = cm.getConfiguration();
		Map nrmConfig = (Map) config.get("glambda-service");
		service = (String) nrmConfig.get("service");
		domain = (String) nrmConfig.get("domain");
		DN = (String) nrmConfig.get("user");
		// credential = (String) nrmConfig.get("password");
		credential = null;
		adjustTime = Integer.parseInt((String) nrmConfig.get("offset"));
	    } catch (Exception ex) {
                ex.printStackTrace();
                System.exit(1);
	    }
	    System.err.println("== GlambdaTranslator:loadConfig:end");
	}
    }

    private FReservation getReservation(FReservationReqParams req) {
	if (req == null) return null;

	FReservation resv = new FReservation();

	resv.setDescriptors(req.getDescriptors());
	resv.setActivationTime(req.getActivationTime());
	resv.setDuration(req.getDuration());
	resv.setBandwidth(req.getBandwidth()/bwunit);
	resv.setSrcEndpoint(req.getSrcEndpoint());
	resv.setDstEndpoint(req.getDstEndpoint());
	resv.setSrcVlanTag(req.getSrcVlanTag());
	resv.setDstVlanTag(req.getDstVlanTag());

	return resv;
    }

    private void convertStatus(FReservation resv, ReservationStatusType status)
    {
	if (status == null || resv == null) return;
	String reservationId = resv.getReservationId();

	if (status == ReservationStatusType.CREATED) {
	    resv.setReservationStatus(FReservationStatus.RESERVING);
	    resv.setActivationStatus(FActivationStatus.INACTIVE);
	} else if (status == ReservationStatusType.RESERVED) {
	    resv.setReservationStatus(FReservationStatus.RESERVED);
	    resv.setActivationStatus(FActivationStatus.INACTIVE);
	} else if (status == ReservationStatusType.ACTIVATED) {
	    resv.setReservationStatus(FReservationStatus.RESERVED);
	    resv.setActivationStatus(FActivationStatus.ACTIVE);
	} else if (status == ReservationStatusType.RELEASED) {
	    FActivationStatus as = resv.getActivationStatus();
	    if (as == FActivationStatus.ACTIVE) {
		resv.setReservationStatus(FReservationStatus.FINISHED);
	    } else {
		resv.setReservationStatus(FReservationStatus.RELEASED);
	    }
	    resv.setActivationStatus(FActivationStatus.INACTIVE);
	    
	    rms.remove(reservationId);
	    subkeys.remove(reservationId);
	    /* keep reservation, do not call resvs.remove(reservationId) */

	} else if (status == ReservationStatusType.ERROR) {
	    resv.setReservationStatus(FReservationStatus.FAILED);
	    resv.setActivationStatus(FActivationStatus.FAILED);

	    rms.remove(reservationId);
	    subkeys.remove(reservationId);
	    /* keep reservation, do not call resvs.remove(reservationId) */
	}
    }
}
